package cn.springboot.erp.aspect;

import cn.springboot.erp.annotation.Log;
import cn.springboot.erp.entity.LogInfo;
import cn.springboot.erp.mapper.LogInfoMapper;
import cn.springboot.erp.utils.IpUtil;
import cn.springboot.erp.utils.JWTUtil;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.lang.reflect.Method;

@Aspect
@Component
public class LogAspect {

    @Resource
    private LogInfoMapper logInfoMapper;
    @Resource
    private JWTUtil jwtUtil;


    @Pointcut("@annotation(cn.springboot.erp.annotation.Log)")
    public void point(){}

    /**
     * 配置切点信息，通过在自定义的切点接口上添加@Pointcut注解，在注解上配置的自定义的注解细信息
     * 在目标接口上添加自定义注解
     */
    @Around("point()")
    private Object aroundAdvice(ProceedingJoinPoint proceedingJoinPoint){

        Object proceed = null;
        try {
            // 在方法执行前获取当前系统时间
            long start = System.currentTimeMillis();
            proceed = proceedingJoinPoint.proceed();
            // 在方法执行完成后获取当前系统事件
            long end = System.currentTimeMillis();
            /**
             * 获取方法的耗时时间 timeConsuming
              */
            long timeConsuming = end - start;
            /**
             * 获取方法的参数 params
              */
            // 获取参数
            Object[] args = proceedingJoinPoint.getArgs();
            // 将参数转换为字符串
            String params = null;
            if (args.length>=0){
                params = StringUtils.arrayToCommaDelimitedString(args);
            }
            /**
             * 获取在目标方法上添加的注解
             * 可以得到 操作的模块和操作描述信息 description model
             */
            // 获取目标方法对象
            MethodSignature signature = (MethodSignature) proceedingJoinPoint.getSignature();
            // 获取方法
            Method method = signature.getMethod();
            // 获取方法上的注解
            Log annotation = method.getAnnotation(Log.class);
            // 获取注解上的描述信息
            String description = annotation.description().getDescription();
            // 获取注解上的模块信息
            String model = annotation.model();
            /**
             * 从请求中获取 操作人、ip地址、请求路径 username、ip、url
             */
            // 获取request对象
            ServletRequestAttributes requestAttributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
            HttpServletRequest request = requestAttributes.getRequest();
            // 获取请求头中的token
            String token = request.getHeader("authorization");
            // 获取token中的用户名
            String username = (String) jwtUtil.getClaims(token).get("username");
            // 通过request对象获取url地址
            String url = request.getServletPath();
            String ip = IpUtil.getIp(request);

            /**
             * 将得到的数据封装成 LogInfo对象
             */
            LogInfo logInfo = new LogInfo();
            logInfo.setTimeConsuming(timeConsuming);
            logInfo.setParams(params);
            logInfo.setDescription(description);
            logInfo.setModel(model);
            logInfo.setUrl(url);
            logInfo.setIp(ip);
            logInfo.setUsername(username);

            // 添加日志信息
            logInfoMapper.insert(logInfo);
        } catch (Throwable e) {
            throw new RuntimeException(e);
        }
        return proceed;
    }
}
